package nachos.threads;

import nachos.ag.BoatGrader;

public class Boat
{
    static BoatGrader bg;
    static boolean debugOutput = false;
    
    public static void selfTest()
    {
		BoatGrader b = new BoatGrader();
		
		//System.out.println("\n ***Testing Boats with only 2 children***");
		//begin(0, 2, b);
	
		//System.out.println("\n ***Testing Boats with 2 children, 1 adult***");
		//begin(1, 2, b);
	
		//System.out.println("\n ***Testing Boats with 3 children, 3 adults***");
		//begin(3, 3, b);
		
		System.out.println("\n ***Testing Boats with only 1 child***");
		begin(0, 1, b);
		
    }

    public static void begin( int adults, int children, BoatGrader b )
    {
		// Store the externally generated autograder in a class
		// variable to be accessible by children.
		bg = b;
	
		// Instantiate global variables here
		boatSide = "O";
		childrenOnBoat = 0;
		adultOnBoat = 0;
		childO = children;
		childM = 0;
		adultO = adults;
		adultM = 0;
		
		s = new Semaphore(0);
		fs = new Semaphore(0);
		lock = new Lock();
		
		//creat the threads here
		for (int i = 0; i < adults; i ++){
			KThread a = new KThread(new Runnable(){
			public void run(){
				AdultItinerary();
			}		
			});
			a.setName("Adult " + i + "Thread");
			a.fork();
		}
		
		for (int i = 0; i < children; i ++){
			KThread a = new KThread(new Runnable(){
			public void run(){
				ChildItinerary();
			}		
			});
			a.setName("Child " + i + "Thread");
			a.fork();
		}
		
		//main thread wait
		fs.P();
		System.out.println("problem  solved!");

    }

    static void AdultItinerary()
    {
		/* This is where you should put your solutions. Make calls
		   to the BoatGrader to show that it is synchronized. For
		   example:
		       bg.AdultRowToMolokai();
		   indicates that an adult has rowed the boat across to Molokai
		*/
		//若在O && 这边只有小于等于1个小孩 && 船在这边 && 为空，则从O到M。
		String mySide = "O";
		while(mySide.equals("O")){
			lock.acquire();
			if (childAtMySide(mySide) <= 1 
					&& boatAtMySide(mySide) 
					&& childrenOnBoat(mySide) == 0 
					&& adultOnBoat(mySide) == 0){
				adultO--;
				adultOnBoat ++;
				bg.AdultRowToMolokai();
				boatSide = "M";
				adultOnBoat --;
				adultM++;
				mySide = "M";
				printStat();
			}
			lock.release();
		}
    }

    static void ChildItinerary()
    {
    	/*
    	 * 若在O：
    	 * 		船在O && 船为空 && （岛上无大人 || 岛上的小孩个数大于等于 2）
    	 * 		船中O && 船中有1个小孩
    	 * 若在M:
    	 * 		船在M && 船为空 && 运输还未完成
    	 * */
    	boolean shouldFinish = false;
    	String mySide = "O";
    	while(mySide.equals("O")){
    		lock.acquire();
    		if (boatAtMySide(mySide)
    				&& childrenOnBoat == 0
    				&& adultOnBoat == 0
    				&& (adultO == 0 || childO >=2)){

    			childO--;
    			childrenOnBoat ++;
    			if (adultO == 0 && childO <= 1){
    				shouldFinish = true;
    			}
    			if (adultO == 0 && childO == 0){
    				bg.ChildRowToMolokai();
    			}
    			else {    				
        			// wait for another child
    				lock.release();
    				s.P();
    				lock.acquire();
    				bg.ChildRideToMolokai();
    			}    			
    			childrenOnBoat --;
    			childM++;
    			mySide = "M";
    			
    			printStat();
    			if (shouldFinish){
    				fs.V();
    				break;
    			}
    		}
    		else if (boatAtMySide(mySide)
    				&& childrenOnBoat == 1
    				&& !shouldFinish){    			
    			// wake up the other child and row to another side
    			childO--;
    			childrenOnBoat ++;
    			if (childO == 0 && adultO == 0)
    				shouldFinish = true;
    			s.V();
    			bg.ChildRowToMolokai();
    			boatSide = "M";
    			childrenOnBoat --;
    			childM++;
    			mySide = "M";	
    			printStat();
    		}
    		lock.release();
    		
    		
    		
    		// on M
    		while (mySide.equals("M") && !shouldFinish){
    			lock.acquire();
    			if (boatAtMySide(mySide)
    			&& childrenOnBoat == 0
    			&& adultOnBoat == 0){
    				childM--;
	    			childrenOnBoat ++;
	    			bg.ChildRowToOahu();
	    			boatSide = "O";
	    			childrenOnBoat --;
	    			childO++;
	    			mySide = "O";
	    			printStat();
    			}
    			lock.release();
    		}
    	}
    	
    	
    }
    
    static void printStat(){
    	if (debugOutput)
    		System.out.println("O : " + childO + "child " + adultO + "adult" + "     Boat : " + childrenOnBoat + "child " + adultOnBoat + "adult     M : " + childM + "child " + adultM + "adult     ");
    	return;
    }
    
    static boolean boatAtMySide(String side){
    	return side.equals(boatSide);
    }
    
    static int childrenOnBoat(String side){
    	if (boatAtMySide(side)){
    		return childrenOnBoat;
    	}
    	else return -1;
    }
    
    static int adultOnBoat(String side){
    	if (boatAtMySide(side)){
    		return adultOnBoat;
    	}
    	else return -1;
    }
    
    static int childAtMySide(String s){
    	if (s.equals("O"))
    		return childO;
    	else 
    		return childM;
    }
    
    static int adultAtMySide(String s){
    	if (s.equals("O"))
    		return adultO;
    	else 
    		return adultM;
    }
    
    static String boatSide;
    static int childrenOnBoat, adultOnBoat;
    static int childO, childM, adultO, adultM;
    
    static Lock lock;
    static Semaphore s, fs;
    
}